// --------------------------------------------------------------------------------------------------------------------
// <copyright file="frmItemLoadStatus.cs" company="">
//   SmartPlan 2011
// </copyright>
// <summary>
//   Summary description for frmItemLoadStatus.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace DbDiff.WinClient.Forms.Status
{
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Linq;
    using System.Windows.Forms;
    using Common.Comparer;
    using Common.Helper;
    using Common.Model;
    using Helper;

    /// <summary>
    /// The load status class
    /// </summary>
    public class FrmItemLoadStatus : Form
    {
        /// <summary>
        /// The diff const
        /// </summary>
        private const int DIFF = 8;

        /// <summary>
        /// The panelminheight.
        /// </summary>
        private const int PANELMINHEIGHT = 141;

        /// <summary>
        /// The panelmaxheight.
        /// </summary>
        private const int PANELMAXHEIGHT = 300;

        /// <summary>
        /// The groupminheight.
        /// </summary>
        private const int GROUPMINHEIGHT = 160;

        /// <summary>
        /// The labelheight.
        /// </summary>
        private const int LABELHEIGHT = 16;

        /// <summary>
        /// The closebuttontop.
        /// </summary>
        private const int CLOSEBUTTONTOP = 216;

        /// <summary>
        /// The controlnameprefix.
        /// </summary>
        private const string CONTROLNAMEPREFIX = "lbl";

        /// <summary>
        /// The picturecontrolnameprefix.
        /// </summary>
        private const string PICTURECONTROLNAMEPREFIX = "pct";

        /// <summary>
        /// The leftpositiondefault.
        /// </summary>
        private const int LEFTPOSITIONDEFAULT = 20;

        /// <summary>
        /// The _must close.
        /// </summary>
        private bool _mustClose;

        /// <summary>
        /// The _event status infos.
        /// </summary>
        private EventStatusInfoCollection _eventStatusInfos;

        /// <summary>
        /// The _frm main.
        /// </summary>
        private FrmMain _frmMain;

        /// <summary>
        /// The db obj 1.
        /// </summary>
        private DatabaseInfoBase dbObj1;

        /// <summary>
        /// The dbi.
        /// </summary>
        private DatabaseObjects dbi;

        /// <summary>
        /// The current db.
        /// </summary>
        private DatabaseInfo currentDb;

        /// <summary>
        /// The is struct query.
        /// </summary>
        private bool isStructQuery;

        /// <summary>
        /// The btn close.
        /// </summary>
        private Button btnClose;

        /// <summary>
        /// The grp main.
        /// </summary>
        private GroupBox grpMain;

        /// <summary>
        /// The panel main.
        /// </summary>
        private Panel panelMain;

        /// <summary>
        /// The grp title.
        /// </summary>
        private GroupBox grpTitle;

        /// <summary>
        /// The lbl title.
        /// </summary>
        private Label lblTitle;
    

        /// <summary>
        /// Required designer variable.
        /// </summary>
        private readonly Container components = null;
        private SelectedDatabase selectedDatabase;

        /// <summary>
        /// Initializes a new instance of the <see cref="FrmItemLoadStatus"/> class.
        /// </summary>
        public FrmItemLoadStatus()
        {
            // Required for Windows Form Designer support
            this.InitializeComponent();

            // TODO: Add any constructor code after InitializeComponent call
            this._eventStatusInfos = new EventStatusInfoCollection();
            this._mustClose = true;
        }

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">
        /// The disposing.
        /// </param>
        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if(this.components != null)
                {
                    this.components.Dispose();
                }
            }

            base.Dispose( disposing );
        }
        
        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.btnClose = new Button();
            this.grpMain = new GroupBox();
            this.panelMain = new Panel();
            this.grpTitle = new GroupBox();
            this.lblTitle = new Label();
            this.grpMain.SuspendLayout();
            this.grpTitle.SuspendLayout();
            this.SuspendLayout();

// btnClose
            this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.btnClose.Location = new Point(176, 216);
            this.btnClose.Name = "btnClose";
            this.btnClose.Size = new Size(80, 23);
            this.btnClose.TabIndex = 0;
            this.btnClose.Text = "Close";

// grpMain
            this.grpMain.Controls.Add(this.panelMain);
            this.grpMain.Location = new Point(8, 48);
            this.grpMain.Name = "grpMain";
            this.grpMain.Size = new Size(416, 160);
            this.grpMain.TabIndex = 2;
            this.grpMain.TabStop = false;

// panelMain
            this.panelMain.AutoScroll = true;
            this.panelMain.Dock = System.Windows.Forms.DockStyle.Fill;
            this.panelMain.Location = new Point(3, 16);
            this.panelMain.Name = "panelMain";
            this.panelMain.Size = new Size(410, 141);
            this.panelMain.TabIndex = 0;

// grpTitle
            this.grpTitle.Controls.Add(this.lblTitle);
            this.grpTitle.Location = new Point(8, 0);
            this.grpTitle.Name = "grpTitle";
            this.grpTitle.Size = new Size(416, 48);
            this.grpTitle.TabIndex = 3;
            this.grpTitle.TabStop = false;

// lblTitle
            this.lblTitle.Location = new Point(8, 16);
            this.lblTitle.Name = "lblTitle";
            this.lblTitle.Size = new Size(400, 24);
            this.lblTitle.TabIndex = 0;
            this.lblTitle.Text = "TITLE";
            this.lblTitle.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;

// frmItemLoadStatus
            this.AutoScaleBaseSize = new Size(5, 13);
            this.CancelButton = this.btnClose;
            this.ClientSize = new Size(430, 246);
            this.ControlBox = false;
            this.Controls.Add(this.grpMain);
            this.Controls.Add(this.btnClose);
            this.Controls.Add(this.grpTitle);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.MinimumSize = new Size(432, 248);
            this.Name = "frmItemLoadStatus";
            this.ShowInTaskbar = false;
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
            this.Shown += new EventHandler(this.frmItemLoadStatus_Shown);
            this.Load += new EventHandler(this.frmItemLoadStatus_Load);
            this.grpMain.ResumeLayout(false);
            this.grpTitle.ResumeLayout(false);
            this.ResumeLayout(false);
        }

        #endregion

        /// <summary>
        /// The init.
        /// </summary>
        /// <param name="title">
        /// The title.
        /// </param>
        /// <param name="frmmain">
        /// The frmmain.
        /// </param>
        /// <param name="mustClose">
        /// The must close.
        /// </param>
        /// <param name="dbObj1">
        /// The db obj 1.
        /// </param>
        /// <param name="dbi">
        /// The dbi.
        /// </param>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        /// <param name="isStructQuery">
        /// The is struct query.
        /// </param>
        public void Init(string title, FrmMain frmmain, bool mustClose, DatabaseInfoBase dbObj1, DatabaseObjects dbi, DatabaseInfo currentDb, bool isStructQuery, SelectedDatabase selectedDatabase) 
        {
            int diff = 0;
            this.selectedDatabase = selectedDatabase;
            this.lblTitle.Text = title;
            this._eventStatusInfos = ThreadHelper.GetEventInfos(false); 
            this._mustClose = mustClose;
            this._frmMain = frmmain;
            this.dbObj1 = dbObj1; this.dbi = dbi; this.currentDb = currentDb; this.isStructQuery = isStructQuery;

            int panelHeight = this._eventStatusInfos.Count * LABELHEIGHT;
            if (panelHeight > PANELMINHEIGHT) 
            {
                if (panelHeight > PANELMAXHEIGHT)
                    panelHeight = PANELMAXHEIGHT;

                diff = panelHeight - PANELMINHEIGHT;
                this.Height = this.MinimumSize.Height + diff;
                this.grpMain.Height = GROUPMINHEIGHT + diff;
                this.panelMain.Height = PANELMINHEIGHT + diff;
                this.btnClose.Top = CLOSEBUTTONTOP + diff;
            }

            this.btnClose.Visible = this._mustClose;
            
            if (! this._mustClose)
            {
                diff = this.btnClose.Top + this.btnClose.Height - (this.grpMain.Top + this.grpMain.Height);
                this.grpMain.Height += diff;
                this.panelMain.Height += diff;
            }
        }

        /// <summary>
        /// The update view.
        /// </summary>
        private void UpdateView() 
        {
            CheckForIllegalCrossThreadCalls = false;
            this.panelMain.Controls.Clear();
            Label siLabel;
            PictureBox pictureBox;

            const int LeftPosition = LEFTPOSITIONDEFAULT;
            int top = 0;
            
            EventStatusInfo si;
            

            foreach (var key in this._eventStatusInfos.OrderBy(z => z.OriginalOrdeer))
            {
                si = key;

                pictureBox = new PictureBox
                                 {
                                     Name = PICTURECONTROLNAMEPREFIX + si.Id, 
                                     Height = 16, 
                                     Width = 16, 
                                     Left = LeftPosition, 
                                     Top = top
                                 };

                siLabel = new Label
                              {
                                  Name = CONTROLNAMEPREFIX + si.Id, 
                                  Text = si.Description.Length == 0 ? si.Id : si.Description, 
                                  Top = top, 
                                  Left = pictureBox.Width + DIFF + LeftPosition, 
                                  Height = LABELHEIGHT, 
                                  TextAlign = ContentAlignment.MiddleLeft
                              };
                siLabel.Width = this.panelMain.Width - siLabel.Left;
                siLabel.Visible = true;

                this.panelMain.Controls.Add(pictureBox);
                this.panelMain.Controls.Add(siLabel);

                top += siLabel.Height;
            }
        }

        /// <summary>
        /// The hide form.
        /// </summary>
        public void HideForm() 
        {
            if (! this._mustClose)
            {
                this.Hide();
            }
        }

        /// <summary>
        /// The frm item load status_ load.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The event args
        /// </param>
        private void frmItemLoadStatus_Load(object sender, EventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
            this.UpdateView();
        }

        /// <summary>
        /// The start async.
        /// </summary>
        public void StartAsync()
        {
            this.LoadAsync(this.dbObj1, this.dbi, this.currentDb, this.isStructQuery, this.selectedDatabase);
        }

        /// <summary>
        /// The update item.
        /// </summary>
        /// <param name="eventStatusId">
        /// The event status id.
        /// </param>
        private void UpdateItem(string eventStatusId)
        {
            CheckForIllegalCrossThreadCalls = false;
            string controlName = CONTROLNAMEPREFIX + eventStatusId;
            string pictureControlName = PICTURECONTROLNAMEPREFIX + eventStatusId;
            string text;

// IconHelper iconHelper;
            Icon icon;

            foreach (Control control in this.panelMain.Controls)
            {
                if ((control is PictureBox) &&
                    (control.Name == pictureControlName))
                {
                    string searchIcon = string.Empty;
                    switch (this._eventStatusInfos[this._eventStatusInfos.FindIndex(z => z.Id == eventStatusId)].State)
                    {
                        case EventState.Waiting:
                            searchIcon = "help";
                            break;
                        case EventState.Running:
                            searchIcon = "right";
                            break;
                        case EventState.Finished:
                            searchIcon = "ok";
                            break;
                        case EventState.Cancelled:
                            searchIcon = "stop";
                            break;
                    }

                    icon = IconHelper.Instance.SearchIcon(searchIcon, IconHelper.IconDisplayType.Smallest);
                    ((PictureBox) control).Image = icon.ToBitmap();
                }
                else if ((control is Label) &&
                         (control.Name == controlName))
                {
                    text = this._eventStatusInfos[this._eventStatusInfos.FindIndex(z => z.Id == eventStatusId)].Description.Length > 0
                               ? this._eventStatusInfos[this._eventStatusInfos.FindIndex(z => z.Id == eventStatusId)].Description
                               : this._eventStatusInfos[this._eventStatusInfos.FindIndex(z => z.Id == eventStatusId)].Id;

                    control.Text = text;
                    break;
                }
            }
        }

        /// <summary>
        /// Sets the state of the event status.
        /// </summary>
        /// <param name="eventStatusId">
        /// Event status id.
        /// </param>
        /// <param name="state">
        /// State.
        /// </param>
        /// <param name="result">
        /// Result.
        /// </param>
        public void SetEventStatusState(string eventStatusId, EventState state, EventResult result)
        {
            int i = this._eventStatusInfos.FindIndex(z => z.Id == eventStatusId);
            if (i > -1)
            {
                this._eventStatusInfos[i].State = state;
                this._eventStatusInfos[i].Result = result;
            }

            this.UpdateItem(eventStatusId);
        }

        /// <summary>
        /// The load async.
        /// </summary>
        /// <param name="dbObj1">
        /// The db obj 1.
        /// </param>
        /// <param name="dbi">
        /// The dbi.
        /// </param>
        /// <param name="currentDb">
        /// The current db.
        /// </param>
        /// <param name="isStructQuery">
        /// The is struct query.
        /// </param>
        private void LoadAsync(DatabaseInfoBase dbObj1, DatabaseObjects dbi, DatabaseInfo currentDb, bool isStructQuery, SelectedDatabase selectedDatabase)
        {
            EventStatusInfoCollection eventStatusInfos = ThreadHelper.GetEventInfos(false);

            dbi.OnStart += this.LoadStartHandler;
            dbi.OnEnd += this.LoadEndHandler;
            dbi.OnItemLoadStart += this.LoadHandler;

            var tm = new ItemLoadThreadManager(
                new StatusFormThread(this, this, string.Format("Loading database: {0}.{1}", currentDb.Server.Name, currentDb.Name), eventStatusInfos), 
                new ItemLoadThread(dbi, dbObj1, ConfigInstance.Config.CompareOptions, isStructQuery, selectedDatabase));
            tm.Start();
        }

        #region Compare / Load event handlers

        /// <summary>
        /// The load start handler.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The event arguments
        /// </param>
        private void LoadStartHandler(object sender, DatabaseItemLoadStateEventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
            this._frmMain.UpdateStatusBar("Loading database objects...");
            switch (e.Index)
            {
                case SelectedDatabase.Left:
                    this._frmMain.Databases.DatabaseLeft.IsUnderFill = true;
                    break;
                case SelectedDatabase.Right:
                    this._frmMain.Databases.DatabaseRight.IsUnderFill = true;
                    break;
            }
        }

        /// <summary>
        /// The load end handler.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The event arguments
        /// </param>
        private void LoadEndHandler(object sender, DatabaseItemLoadStateEventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
            this._frmMain.UpdateStatusBar(string.Empty);
            switch (e.Index)
            {
                case SelectedDatabase.Left:
                    this._frmMain.Databases.DatabaseLeft.IsUnderFill = false;
                    break;
                case SelectedDatabase.Right:
                    this._frmMain.Databases.DatabaseRight.IsUnderFill = false;
                    break;
            }

// this.Close();
        }

        /// <summary>
        /// The load handler.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The event arguments
        /// </param>
        private void LoadHandler(object sender, DatabaseItemLoadEventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
            this._frmMain.UpdateStatusBar(string.Format("Loading {0} ...", e.ObjectType));
            this.UpdateItem(e.InfoIndex.ToString());
        }

        #endregion Compare / Load event handlers

        /// <summary>
        /// The frm item load status_ shown.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The event arguments
        /// </param>
        private void frmItemLoadStatus_Shown(object sender, EventArgs e)
        {
            this.LoadAsync(this.dbObj1, this.dbi, this.currentDb, this.isStructQuery, this.selectedDatabase);
        }
    }
}